/**
 * wait和notify/notifyAll方法只能在同步代码块里用
 *
 * LockSupport是一个线程阻塞工具类
 * LockSupport调用的是Unsafe中的native代码,使用了一种名为Permit（许可）的概念来做到阻塞和唤醒线程的功能，每个线程都有一个许可（permit）
 * LockSupport比Object的wait/notify有两大优势：
 * LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了，实现了线程间的解耦。
 * unpark函数可以先于park调用，所以不需要担心线程间的执行的先后顺序。
 *
 * @see java.util.concurrent.locks.LockSupport
 * @see java.util.concurrent.locks.LockSupport#park()
 * @see java.util.concurrent.locks.LockSupport#park(java.lang.Object)
 * @see java.util.concurrent.locks.LockSupport#parkNanos(long)
 * @see java.util.concurrent.locks.LockSupport#parkNanos(java.lang.Object, long)
 * @see java.util.concurrent.locks.LockSupport#parkUntil(long)
 * @see java.util.concurrent.locks.LockSupport#parkUntil(java.lang.Object, long)
 *
 * @see java.util.concurrent.locks.LockSupport#unpark(java.lang.Thread)
 *
 *
 * 那么Unsafe类是个什么东西呢？Unsafe的全限定名是sun.misc.Unsafe。在源码的注释中我们可以看到：执行低级、不安全操作的方法集合。从名字就知道它是不安全的，它的功能有很多，比如：volatile的读写一个变量的field，有序的写一个变量的field，直接内存操作：申请内存，释放内存，CAS的修改变量等。
 * 本文主要说说park和unpark方法。最简单的理解：park阻塞一个线程，unpark唤醒一个线程。
 * 核心设计原理：“许可”。
 * park方法本质是***消费许可***，如果没有可消费的许可，那么就阻塞当前线程，一直等待，直到阻塞线程的unpark方法被其他线程调用，然后消费许可，当前线程被唤醒，继续执行。
 * unpark方法本质是***生产许可***，一个线程刚创建出来，然后运行，此时是没有许可的，所以unpark方法可以在park方法前调用。下次park方法调用时，直接消费许可，线程不用阻塞等待许可。许可最多只有一个，连续多次调用unpark只能生产一个许可。
 * park方法有几种重载的形式，可以设置等待时间，等待时间可以设置为绝对的或者相对的，超过等待时间，线程会自动被唤醒。
 *
 * 底层实现原理：
 * 在Linux系统下，是用的Posix线程库pthread中的mutex（互斥量），condition（条件变量）来实现的。
 * mutex和condition保护了一个_counter的变量，简单点说：当park时，这个变量被设置为0，当unpark时，这个变量被设置为1。
 * 关于源码，可以看这篇博客：https://blog.csdn.net/weixin_39687783/article/details/85058686
 *
 * 总结：
 * LockSupport的park和unpark方法相比于Synchronize的wait和notify，notifyAll方法：
 * 1.更简单，不需要获取锁，能直接阻塞线程。
 * 2.更直观，以thread为操作对象更符合阻塞线程的直观定义；
 * 3.更精确，可以准确地唤醒某一个线程（notify随机唤醒一个线程，notifyAll唤醒所有等待的线程）；
 * 4.更灵活 ，unpark方法可以在park方法前调用
 */
package cn.jdemo.juc.locksupport;